package org.orz.cloud.core.aop;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.db.Page;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.orz.cloud.common.result.ResultDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 记录每个controller方法的日志
 * @author wrz
 * @date 2019年7月14日
 * @version 1.0
 */
@Component
@Aspect
public class LogAOP {

	private static final Logger LOGGER = LoggerFactory.getLogger(LogAOP.class);

	ThreadLocal<Long> startTime = new ThreadLocal<>();

	/**
	 * 配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
	 */
	@Pointcut("execution(* cn.itcast.*.web..*.*(..))")
	public void aspect(){	}

	/**
	 * 前置增强，在方法执行前会输出该方法的所在类名、方法名、请求参数
	 * @param joinPoint joinPoint
	 */
    @Before(value = "aspect()")
    public void before(JoinPoint joinPoint){
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
		String className = joinPoint.getTarget().getClass().getName();
		String method = joinPoint.getSignature().getName()+"()";
//		LOGGER.info("request.getParameterMap() 	: {}" ,request.getParameterMap());
//		LOGGER.info("joinPoint.getArgs() 	   	: {}" ,JSON.toJSONString(joinPoint.getArgs()));
//		LOGGER.info("request.getQueryString() 	: {}",request.getQueryString());
		String decode = request.getQueryString();
		if(null == decode && null != joinPoint.getArgs()){
			Object[] args = joinPoint.getArgs();
			List<Object> decodeList = Arrays.stream(args)
					.filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse)))
					.collect(Collectors.toList());
			if(CollUtil.isNotEmpty(decodeList)){
				decode = JSON.toJSONString(decodeList);
			}
		}
		startTime.set(System.currentTimeMillis());
		LOGGER.info("==================================request start=========================================");
		LOGGER.info("class  : {}",className);
		LOGGER.info("method : {}",method);
		LOGGER.info("params : {}",decode);
    }

	/**
	 * 返回增强，在方法返回时执行，输出方法的响应报文
	 * @param joinPoint joinPoint
	 * @param output 响应报文
	 */
    @AfterReturning(returning = "output",value = "aspect()")
    public void after(JoinPoint joinPoint, Object output){
		LOGGER.info("time        : {}ms", System.currentTimeMillis()-startTime.get());
		if(output instanceof ResultDTO){
			LOGGER.info("respCode    : {}",((ResultDTO)output).getCode());
			LOGGER.info("respMessage : {}",((ResultDTO)output).getMessage());
			if(((ResultDTO)output).getData() instanceof Page){
				LOGGER.info("data		   : {}", JSON.toJSONString(BeanUtil.beanToMap(((ResultDTO)output).getData())));

			} else {
				LOGGER.info("data 		   : {}", JSON.toJSONString(((ResultDTO)output).getData()));
			}
		}else{
			LOGGER.info("return 	 : {}",output.toString());
		}
		LOGGER.info("==================================request end=========================================");
	}

}
